﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Behavior : MonoBehaviour
{
    [Header("基本属性")]
    [SerializeField] private float speed;               //移动时的速度
    [SerializeField] private int maxJumpStep;           //最大连续跳跃次数
    [SerializeField] private float jumpSpeed;           //跳跃时的垂直速度
    [SerializeField] private int max_hp;                //生命值上限
    [Header("补偿速度")]
    [SerializeField] private float attackSpeed;         //攻击时的自动移动速度
    [Header("地图碰撞")]
    [SerializeField] private LayerMask layer01;         //人物不可以从下方穿过的地图区域的图层
    [SerializeField] private LayerMask layer02;         //人物可以从下方跳跃穿过的图层
    [SerializeField] private float check_dis;           //射线检测的长度
    [Space]

    private Animator animator;
    private new BoxCollider2D collider;
    private Rigidbody2D rbody;

    private Vector2 centerPos;                          //人物的中心点坐标(碰撞器的中心点坐标)
    private int jumpStep;                               //当前连续跳跃次数
    private bool isGround;                              //是否在地面上
    private bool isAttack;                              //人物前方是否接触到障碍物
    private bool beHit;                                 //受击状态
    private int hp;                                     //当前生命值

    // Start is called before the first frame update
    void Start()
    {
        animator = gameObject.GetComponent<Animator>();
        collider = gameObject.GetComponent<BoxCollider2D>();
        rbody = gameObject.GetComponent<Rigidbody2D>();

        hp = max_hp;
        CenterPosUpdate();
    }

    // Update is called once per frame
    void Update()
    {
        if (transform.localScale.x == 0)
        {
            Debug.LogError("transform.localScale.x == 0");
            return;
        }

        CenterPosUpdate();
                                                                                                                                  
        //如果前方接触到了障碍物,则把水平速度置为0
        if (CheckFront(ref layer01))
        {
            SetVelocity_X(0);
        }

        isGround = IsGround(ref layer01) || IsGround(ref layer02);
        animator.SetBool("IsGround", isGround);
        animator.SetFloat("Horizontal", rbody.velocity.x);
        animator.SetFloat("Vertical", rbody.velocity.y);

        if (isGround && rbody.velocity.y < 0)
        {
            SetVelocity_Y(0);
        }
    }

    /// <summary>
    /// 更新人物中心点(碰撞器的坐标)的坐标
    /// </summary>
    void CenterPosUpdate()
    {
        if (transform.localScale.x > 0)
            centerPos = centerPos = new Vector2(transform.position.x, transform.position.y) + collider.offset;
        else
            centerPos = centerPos = new Vector2(transform.position.x, transform.position.y) + new Vector2(-collider.offset.x, collider.offset.y);
    }
    
    /// <summary>
    /// 跟新刚体的x方向速度
    /// </summary>
    /// <param name="x"></param>
    private void SetVelocity_X(float x)
    {
        rbody.velocity = new Vector2(x, rbody.velocity.y);
    }

    /// <summary>
    /// 更新刚体的y方向速度
    /// </summary>
    /// <param name="y"></param>
    private void SetVelocity_Y(float y)
    {
        rbody.velocity = new Vector2(rbody.velocity.x, y);
    }

    /// <summary>
    /// 更新刚体的x,y速度
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    private void SetVelocity(float x,float y)
    {
        rbody.velocity = new Vector2(x, y);
    }

    /// <summary>
    /// 根据刚体的水平速度,改变localScale.x的值来实现图像的翻转
    /// 为了使图像看起来是沿着碰撞器的x坐标进行翻转的
    /// 在更改localScale后要接着改变position.x的值
    /// </summary>
    void TowardsUpdate()
    {
        if (rbody.velocity.x == 0) return;
        else Towards((rbody.velocity.x > 0) ? (1f) : (-1f));
    }

    /// <summary>
    /// 改变物体的方向
    /// </summary>
    void Towards(float direction)
    {
        if (direction == 0) return;

        //判断当前方向是否与改变后方向相反
        if (transform.localScale.x * direction < 0)
        {
            //Debug.Log((transform.localScale.x < 0).ToString()+" "+ (direction < 0).ToString());
            transform.localScale = new Vector3(-transform.localScale.x, transform.localScale.y, transform.localScale.z);

            if (transform.localScale.x > 0)
                transform.position -= new Vector3(collider.offset.x * 2f, 0, 0);
            else
                transform.position += new Vector3(collider.offset.x * 2f, 0, 0);

            CenterPosUpdate();
        }
    }

    /// <summary>
    /// 检查前方是否碰到了某图层的物体
    /// 分别在刚体顶端和底端发射射线
    /// </summary>
    bool CheckFront(ref LayerMask layer)
    {
        float dis = collider.size.x / 2 + check_dis;
        Vector2 rayPos, direction;
        RaycastHit2D hit;

        if (transform.localScale.x > 0) direction = Vector2.right;
        else direction = Vector2.left;

        rayPos = centerPos + new Vector2(0, collider.size.y / 2 - 0.001f);
        hit = Physics2D.Raycast(rayPos, direction, dis, layer);
        if (hit.collider != null) return true;

        rayPos = centerPos + new Vector2(0, 0.001f - collider.size.y / 2);
        hit = Physics2D.Raycast(rayPos, direction, dis, layer);
        if (hit.collider != null) return true;

        return false;
    }


    /// <summary>
    /// 检查是否能继续前进
    /// </summary>
    /// <returns></returns>
    public bool CanGoAhead()
    {
        RaycastHit2D hit;
        Vector2 rayPos;
        float dis = check_dis + collider.size.y / 2;

        if (transform.localScale.x > 0) rayPos = centerPos + new Vector2(collider.size.x / 2, 0);
        else rayPos = centerPos + new Vector2(-collider.size.x / 2, 0);

        //前方没有地面了返回false
        hit = Physics2D.Raycast(rayPos, Vector2.down, dis, layer01);
        if (hit.collider == null) return false;

        //前方有障碍也返回false
        if (CheckFront(ref layer01)) return false;

        return true;
    }

    /// <summary>
    /// 判断人物是否在地上
    /// 这里用到Raycast函数，向场景中的碰撞体投射射线，需要射线的2D起点、射线2D方向向量、射线投射的最大距离
    /// 函数返回一个 RaycastHit 对象，该对象引用了射线命中的碰撞体（如果未命中任何对象，则结果的碰撞体属性将为 NULL
    /// 这里在人物刚体的左下角和右下角分别判断一次，有一个有返回值说明人物至少一只脚踩在地上
    /// </summary>
    bool IsGround(ref LayerMask layer)
    {
        float dis = collider.size.y / 2 + check_dis;
        Vector2 rayPos;
        RaycastHit2D hit;

        rayPos = centerPos + new Vector2(-collider.size.x / 2, 0);
        hit = Physics2D.Raycast(rayPos, -Vector2.up, dis, layer);
        if (hit.collider != null) return true;

        rayPos = centerPos + new Vector2(collider.size.x / 2, 0);
        hit = Physics2D.Raycast(rayPos, -Vector2.up, dis, layer);
        if (hit.collider != null) return true;

        return false;
    }

    public void Move(float direction)
    {
        if (this.tag.Contains("Enemy")) Debug.Log("Move"+direction.ToString());
        if (beHit) return;      //正在闪烁,无法下达移动命令

        if (!isAttack)
        {
            SetVelocity_X(direction * speed);
        }

        if (direction != 0)  TowardsUpdate();
    }

    public void Attack()
    {
        if (beHit) return;      //正在闪烁,无法下达攻击命令

        if (!isAttack)
        {
            isAttack = true;
            animator.SetTrigger("Attack");

            float direction = (transform.localScale.x > 0) ? (1f) : (-1f);
            SetVelocity_X(direction * attackSpeed);
        }
    }

    public void AttackOver()
    {
        if (isAttack)
        {
            //Debug.Log("AttackOver");
            isAttack = false;
            SetVelocity_X(0);
        }
    }

    public void Jump()
    {
        if (isAttack || beHit) return;
        if (isGround)
        {
            jumpStep = 0;
        }
        if (jumpStep<maxJumpStep)
        {
            jumpStep++;
            animator.SetTrigger("Jump");

            SetVelocity_Y(jumpSpeed);
        }
    }

    public void BeHit(float direction)
    {
        if (!beHit)
        {
            beHit = true;
            //收到攻击后人物朝向攻击方向
            Towards(direction);
            SetVelocity_X(-direction * attackSpeed * 0.5f);

            hp--;
            if (hp <= 0)
            {
                animator.SetTrigger("Dead");
                SetVelocity_X(0);
            }
            else animator.SetTrigger("BeHit");
        }
    }

    public void BeHitOver()
    {
        if (beHit)
        {
            beHit = false;
            SetVelocity_X(0);
        }
    }

    public void Dead()
    {
        SetVelocity(0,0);
        Destroy(this.gameObject);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        //Debug.Log(this.tag.ToString()+"BeHit");
        //Debug.Log(collision.tag);
        if (collision.tag.Contains("AttackArea"))
        {
            return;
        }

        if (!gameObject.CompareTag(collision.tag))
        {
            if (transform.localScale.x > 0)
                collision.gameObject.GetComponent<Behavior>().BeHit(-1f);
            else
                collision.gameObject.GetComponent<Behavior>().BeHit(1f);
        }
    }

    public bool IsAttack()
    {
        return isAttack;
    }

    public Vector2 GetCenterPos()
    {
        return centerPos;
    }
}
